import { ts,  rule, DslRule } from "qvog-dsl";
import { adapter } from "../../../../../src/adapter/Adapter";
import { AstMatcher, AstMatcherCallback, BaseChecker } from "../../../../../src/Index";
import { ArkFile, AstTreeUtils } from "arkanalyzer";

import { assert, beforeAll, describe, test } from 'vitest';
import { CHECK_MODE, testCaseCheck } from '../../common/testCommon';
import ArrayTypeCheckDSL from "../../../../../src/checker/dsl/ArrayTypeCheck";
import { CheckEntry, Rule } from '../../../../../src/Index';

function iterateAst(arkFile: ArkFile, matchers: [AstMatcher, AstMatcherCallback][]): void {
    const root = AstTreeUtils.getSourceFileFromArkFile(arkFile);
    root.forEachChild((node => {
        matchAstNode(node as any, matchers);
    }));
}

function matchAstNode(node: ts.Node, matchers: [AstMatcher, AstMatcherCallback][]): void {
    for (const [matcher, callback] of matchers) {
        if (matcher.match(node)) {
            callback(node);
        }
    }
    node.forEachChild((child) => {
        matchAstNode(child, matchers);
    });
}

let realPath: string = '';
let checkEntry: CheckEntry;

beforeAll(async () => {
    const rule: Rule = new Rule('');
    checkEntry = await testCaseCheck('./test/unittest/sample/ArrayTypeCheckDSL', rule, CHECK_MODE.FILE2CHECK, ArrayTypeCheckDSL, false, true);
    realPath = checkEntry.scene.getRealProjectDir()
})

describe('matchTest', () => {
    test('matchTest_001', () => {
        let arkFile: ArkFile = checkEntry.fileChecks[0].arkFile;
        assert.isDefined(arkFile, 'The file path is error.');
        let dslRule: DslRule = rule()
            .match((node): node is ts.VariableDeclaration => ts.isVariableDeclaration(node))
            .when((node): boolean => {
                assert.isTrue(ts.isVariableDeclaration(node));
                return false;
            })
            .report({
                severity: 'SEVERITY',
                description: 'DESCRIPTION',
                docPath: 'DOC_PATH'
            });


        let checker: BaseChecker = adapter.loadDslRule(dslRule);
        checker.rule = new Rule("test1", 1);
        const matcherCallbacks = checker.registerMatchers();
        let astMatchers: [AstMatcher, AstMatcherCallback][] = [];
        matcherCallbacks.forEach(obj => {
            const matcher = obj.matcher;
            const callback = obj.callback;
            astMatchers.push([matcher as AstMatcher, callback as AstMatcherCallback]);
        });
        iterateAst(arkFile, astMatchers);
    }),
    test('matchTest_002', () => {
        let arkFile: ArkFile = checkEntry.fileChecks[1].arkFile;
        assert.isDefined(arkFile, 'The file path is error.');
        let dslRule: DslRule = rule()
            .match((node): node is ts.VariableStatement => ts.isVariableStatement(node))
            .when((node): boolean => {
                assert.isTrue(ts.isVariableStatement(node));
                return false;
            })
            .report({
                severity: 'SEVERITY',
                description: 'DESCRIPTION',
                docPath: 'DOC_PATH'
            });


        let checker: BaseChecker = adapter.loadDslRule(dslRule);
        checker.rule = new Rule("test2", 1);
        const matcherCallbacks = checker.registerMatchers();
        let astMatchers: [AstMatcher, AstMatcherCallback][] = [];
        matcherCallbacks.forEach(obj => {
            const matcher = obj.matcher;
            const callback = obj.callback;
            astMatchers.push([matcher as AstMatcher, callback as AstMatcherCallback]);
        });
        iterateAst(arkFile, astMatchers);
    })
})